<!--
 * @Author: zw 775925302@qq.com
 * @Date: 2023-02-17 22:39:12
 * @LastEditors: zw 775925302@qq.com
 * @LastEditTime: 2023-02-19 12:13:26
 * @Description: 拖拽组件

 层布局：
   1. 最外层是个容器对象，里面又是一个个拖拽对象
-->
<template>
  <div
    :ref="dragRoot"
    :style="getCmpStyle"
    @mouseenter.stop="mouseEnter"
    @mousedown.stop="selectWidget"
    @mouseleave.stop="mouseLeave"
    :class="[getWidgetSelectClass, 'box']"
  >
    <div :ref="drop">
      <div class="cRootRelation">
        <slot></slot>
      </div>
    </div>
    <div v-if="getIsWidgetSelect">
      <div class="cBottomMiddle" @mousedown.passive="handleDragYStartEvent"></div>
      <div class="cRightMiddle" @mousedown.passive="handleDragXStartEvent"></div>
      <div class="cRightBottom" @mousedown.passive="handleDragXYStartEvent"></div>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, computed, inject, onMounted, ref } from "vue";
import type { PropType } from "vue";
import { useWidget } from "@/hooks/lowcode/useWidget";
import { useDrop, useDrag } from "vue3-dnd";
import { getEmptyImage } from "react-dnd-html5-backend";
import { deepClone, generateId } from "@/utils/StrUtil";
import CmpConfig from "@/components-designer/indexCmpConfig";
import { designEditKey } from "@/hooks/lowcode/keys";
import type { TypeDesignProvide, TypeWidget } from "@/types/TypeDesign";
import type { DragSourceMonitor, XYCoord } from "vue3-dnd";

export default defineComponent({
  name: "DragLayout",
  props: {
    mwidget: {
      type: Object as PropType<TypeWidget>,
      default: () => {},
    },
    preview: {
      type: Boolean,
      default: false,
    },
    subCmpScale: {
      type: Boolean,
      default: false,
    },
  },
  emits: [],

  setup(props) {
    let {
      selectWidget,
      mouseEnter,
      mouseLeave,
      getWidgetSelectClass,
      isResizing,
      getIsWidgetSelect,
      handleDragXYStartEvent,
      handleDragXStartEvent,
      handleDragYStartEvent,
    } = useWidget(props.mwidget);
    let {
      initScreenPos,
      setDesignSelectWidget,
      removeWidgetFromDesignWidgetList,
      removeWidgetFromFatherWidgets,
      setSnapToGrid,
    } = inject(designEditKey) as TypeDesignProvide;

    const [collectDrop, drop] = useDrop(() => ({
      accept: ["component", "element"],
      canDrop(item: TypeWidget, monitor) {
        if (item.cmpType === "layout") {
          //解决不支持布局停靠
          return false;
        }
        return true;
      },
      // hover(item, monitor) {
      //   console.log("DragLayout------hover------", item.id)
      // },
      drop(item: TypeWidget, monitor) {
        console.log("DragLayout------------", item.id);

        if (item.cmpType === "layout") {
          return;
        }

        if (monitor.getItemType() === "component") {
          addWidgetFromCmpAreaMoveToDesigner(item, monitor);
          return;
        }

        console.log("DragLayout------enter------", item, props.mwidget.id);

        /**
         *   拖完后停放
         * 1. 如果这个元素是没有fatherWidget,说明他是从主容器拖入到当前容器，
         *    a. 设置fatherWidget为当前widget,并且添加到widgetList中
         *    b. 从主容器移除到当前widget
         * 2. 有fatherWidget, 但是fatherWidget.id不等于当前容器的ID
         *
         * 3.
         *
         */

        /**
         *  处理没有父节点情况：
         *  1. 组件拖进来
         *  2. 容器拖进来
         */
        if (!item.fatherWidget) {
          //没有父节点
          //第一中情况
          item.fatherWidget = props.mwidget;
          item.style.left = Math.round(
            monitor.getSourceClientOffset()!.x - props.mwidget.style.left - initScreenPos.value.x
          );
          item.style.top = Math.round(
            monitor.getSourceClientOffset()!.y - props.mwidget.style.top - initScreenPos.value.y
          );

          props.mwidget.widgetList.push(item);
          setDesignSelectWidget(item);
          setSnapToGrid(item);

          //从主容器中移除
          removeWidgetFromDesignWidgetList(item.id);

          console.log(props.mwidget);
        } else if (item.fatherWidget && item.fatherWidget.id !== props.mwidget.id) {
          console.log("remove-------->");
          // 把他的父容器中移除自己
          removeWidgetFromFatherWidgets(item.id, item.fatherWidget);
          // 把他的父容器设置为当前父容器
          item.fatherWidget = props.mwidget;
          // 当前容器添加它为子组件
          props.mwidget.widgetList.push(item);
          setDesignSelectWidget(item);
          // 修改坐标
          item.style.left = Math.round(
            monitor.getSourceClientOffset()?.x - props.mwidget.style.left - initScreenPos.value.x
          );
          item.style.top = Math.round(
            monitor.getSourceClientOffset()?.y - props.mwidget.style.top - initScreenPos.value.y
          );
          setSnapToGrid(item);
        } else {
          console.log("base-------->");
          const delta = monitor.getDifferenceFromInitialOffset() as XYCoord;
          item.style.left = Math.round(item.style.left + delta.x);
          item.style.top = Math.round(item.style.top + delta.y);
          setSnapToGrid(item);
        }
      },
      collect: (monitor) => ({
        isOverCurrent: monitor.isOver({ shallow: true }),
        item: monitor.getItem(),
      }),
    }));

    const [collect, dragRoot, previewRef] = useDrag(() => ({
      type: "element",
      item: props.mwidget,
      collect: (monitor: DragSourceMonitor) => ({
        isDragging: monitor.isDragging(),
      }),
      canDrag: () => {
        if (isResizing.value || props.subCmpScale) {
          return false;
        }
        return true;
      },
    }));

    /**
     *  //说明当前元素是从组件区拖放到设计器内
     * @param item
     * @param monitor
     */
    const addWidgetFromCmpAreaMoveToDesigner = (item: TypeWidget, monitor) => {
      //说明当前元素是从组件区拖放到设计器内

      var newOrigin = deepClone(item);
      newOrigin.id = generateId();
      let _widget = Object.assign(newOrigin, deepClone(CmpConfig[newOrigin.component])) as TypeWidget;
      _widget.style.left = Math.round(
        monitor.getSourceClientOffset()?.x - props.mwidget.style.left - initScreenPos.value.x
      );
      _widget.style.top = Math.round(
        monitor.getSourceClientOffset()?.y - props.mwidget.style.top - initScreenPos.value.y
      );
      _widget.fatherWidget = props.mwidget;
      props.mwidget.widgetList.push(_widget);
      setDesignSelectWidget(_widget);
    };

    // onMounted(() => {
    //   previewRef(getEmptyImage(), { captureDraggingState: true }); //清空默认的预览页面
    // });

    const getCmpStyle = computed(() => {
      if (props.preview) {
        return {
          backgroundColor: "#f2f2f2",
        };
      } else {
        let isCanOver = false;
        if (
          collectDrop.value &&
          collectDrop.value.isOverCurrent &&
          collectDrop.value.item &&
          collectDrop.value.item.cmpType === "component"
        ) {
          isCanOver = true;
        }

        return {
          left: `${props.mwidget.style.left}px`,
          top: `${props.mwidget.style.top}px`,
          opacity: collect.value.isDragging ? 0 : 1,
          height: collect.value.isDragging ? 0 : "",
          backgroundColor: isCanOver ? "#fcb440" : "#f2f2f2",
        };
      }
    });

    return {
      selectWidget,
      mouseEnter,
      mouseLeave,
      getWidgetSelectClass,
      getIsWidgetSelect,
      handleDragYStartEvent,
      handleDragXStartEvent,
      handleDragXYStartEvent,

      drop,
      dragRoot,
      getCmpStyle,
    };
  },
});
</script>
<style scoped lang="scss">
.box {
  position: absolute;
}

.cRootRelation {
  position: relative;
}

.cBottomMiddle {
  position: absolute;
  width: 4px;
  height: 4px;
  background-color: transparent;
  left: 0;
  right: 0;
  bottom: -4px;
  margin: auto;
  cursor: ns-resize;
  border-radius: 50%;
  border: 1px solid red;
}

.cRightMiddle {
  position: absolute;
  width: 4px;
  height: 4px;
  background-color: transparent;
  top: 0;
  bottom: 0;
  right: -4px;
  margin: auto;
  cursor: ew-resize;
  border-radius: 50%;
  border: 1px solid red;
}

.cRightBottom {
  position: absolute;
  width: 4px;
  height: 4px;
  background-color: transparent;
  bottom: -4px;
  right: -4px;
  margin: auto;
  cursor: nwse-resize;
  border-radius: 50%;
  border: 1px solid red;
}
</style>
